package kinectData.simulator;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Scanner;

import kinectData.models.ProjectSettings;

/**
 * Simulates recorded data streamed from the Kinect. 
 * 
 * @author Markus L�chtefeld (loechti)
 */
public class SimulatorThread extends Thread {

	private ArrayList<Event> events;
	private float millisperPercent;
	private int currentPosition = 0;
	private SimulatorGUI sGUI;
	
	public SimulatorThread(String path, SimulatorGUI sGUI){
		this.sGUI = sGUI;
		this.events = parseEvents(path);
		long first = events.get(0).getTime();
		long last = events.get(events.size() - 1).getTime();
		this.millisperPercent = (last - first) / 100;  
	}
	
	private ArrayList<Event> parseEvents(String filename) {
		ArrayList<Event> events = new ArrayList<Event>();
		try {
			InputStream input = new FileInputStream(filename);
			Scanner inputScanner = new Scanner(input);
			while (inputScanner.hasNext()) {
				String line = inputScanner.nextLine().trim();
				Scanner lineScanner = new Scanner(line).useDelimiter("#");
				long time = lineScanner.nextLong();
				Event.Type type = lineScanner.hasNextInt() ? Event.Type.SKELETON : Event.Type.DEVICE;
				String data = lineScanner.nextLine();
				events.add(new Event(time, data, type));
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return events;
	}
	
	public void sendToTable(String message, int port) {
		try {
			InetAddress serverAddr = InetAddress.getByName("127.0.0.1");
			DatagramSocket socket = new DatagramSocket();
			byte[] buf = (message).getBytes();
			DatagramPacket packet = new DatagramPacket(buf, buf.length, serverAddr, port);
			socket.send(packet);
		} catch (Exception e) {
			System.err.println("Failed to send message " + e.getMessage());
		}
	}
	
	public void run() {
		if (events.isEmpty()) {
			return;
		}
		long lastTime = events.get(0).getTime();
		// Stop when all events have played.
		while (currentPosition < events.size()) {
			Event event = events.get(currentPosition);
			try {
				Thread.sleep(Math.abs(event.getTime() - lastTime));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			lastTime = event.getTime();
			sendToTable(event.getMessage(), event.getType() == Event.Type.DEVICE ? 
				ProjectSettings.ACCELEROMETER_PORT : ProjectSettings.KINECT_PORT);
			currentPosition++;
			int sliderPosition = (int)((lastTime - events.get(0).getTime()) / millisperPercent);
			sGUI.updateSlider(sliderPosition);
		}
		sGUI.enableButton();
	}
	
	public synchronized void gotoPosition(int p) {
		long startTime = events.get(0).getTime();
		long calcPosition = startTime  + (long)(p * millisperPercent);
		long closestEvent = Long.MAX_VALUE;
		int closestPosition = 0;
		for (int i = 0; i < events.size(); i++){
			Event event = events.get(i); 
			if (event.getTime() == calcPosition) {
				currentPosition = i;
				return;
			} else if (Math.abs(event.getTime() - calcPosition) < closestEvent) {
				closestEvent = Math.abs(event.getTime() - calcPosition);
				closestPosition = i;
			}
		}
		currentPosition = closestPosition;
	}
}
